﻿/************************************************************************/
/* Package : XadiJson                                                   */
/* Description: Yet another Json parser.                                */
/*                                                                      */
/* Author  : XadillaX(admin@xcoder.in)                                  */
/* Date    : 2012/07/20                                                 */
/* Blog    : http://xcoder.in/                                          */
/*                                                                      */
/************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ZMenFM.Utils.Json
{
    public enum ZMJsonElementType
    {
        XJET_VALUE,
        XJET_OBJECT,
        XJET_ARRAY
    }

    public class ZMJsonElement
    {
        #region 类成员对象
        protected String key = "";
        protected String value = "";
        public Dictionary<String, ZMJsonElement> Objects = new Dictionary<string, ZMJsonElement>();
        public List<ZMJsonElement> Children = new List<ZMJsonElement>();
        protected ZMJsonElementType type = ZMJsonElementType.XJET_VALUE;
        #endregion

        #region 设置/获取元素信息
        public void SetKey(String k) { key = k; }
        public String GetKey() { return key; }

        public void SetType(ZMJsonElementType t) { type = t; }
        public new ZMJsonElementType GetType() { return type; }

        public void SetValue(String v) { value = v; }
        public String GetValue() { return value; }
        #endregion

        #region 获取元素 (函数)
        public ZMJsonElement GetObject(String key) { return this[key]; }
        public ZMJsonElement GetChild(int idx) { return this[idx]; }
        #endregion

        #region 获取元素 (索引)
        /// <summary>
        /// Json数组元素索引
        /// </summary>
        /// <param name="idx">下标</param>
        /// <returns>Json元素</returns>
        public ZMJsonElement this[int idx]
        {
            get
            {
                if (idx >= Children.Count) return null;
                return Children.ElementAt(idx);
            }
        }

        /// <summary>
        /// Json对象元素索引
        /// </summary>
        /// <param name="key">键名</param>
        /// <returns>Json元素</returns>
        public ZMJsonElement this[String key]
        {
            get
            {
                if (!Objects.ContainsKey(key)) return null;
                return Objects[key];
            }
        }
        #endregion
    }

    public class ZMJsonReader
    {
        private ZMJsonElement root = null;
        private String ParsingString;
        private int ParsingPosition;

        /// <summary>
        /// 构造函数
        /// </summary>
        public ZMJsonReader()
        {
            root = null;
        }

        #region 外部调用函数
        /// <summary>
        /// 获取Json根
        /// </summary>
        /// <returns>根元素</returns>
        public ZMJsonElement GetRoot()
        {
            return root;
        }

        /// <summary>
        /// 从Json字符串载入
        /// </summary>
        /// <param name="jsonString">Json字符串</param>
        /// <returns>是否载入成功</returns>
        public bool Load(String jsonString)
        {
            ParsingString = jsonString;
            ParsingString = ParsingString.Trim();
            if (ParsingString[0] != '{')
            {
                ParsingString = "{" + ParsingString + "}";
            }
            ParsingPosition = 0;
            ParsingString = "\"\":" + ParsingString + "\n";

            root = new ZMJsonElement();
            root.SetType(ZMJsonElementType.XJET_OBJECT);

            root = ParserElement();
            if (null == root) return false;
            else return true;
        }
        #endregion

        #region dump函数 (调试用)
        /// <summary>
        /// DUMP函数 (被显式 DUMP 调用并递归)
        /// </summary>
        /// <param name="ele">元素</param>
        /// <param name="lv">等级</param>
        private void dump(ZMJsonElement ele, int lv)
        {
            if (null == ele) return;

            /** 缩进 */
            for (int i = 0; i < lv; i++) Console.Write("    ");

            if (0 != lv)
            {
                if (ele.GetKey() != "") Console.Write(ele.GetKey() + ": ");
            }
            else
            {
                Console.Write("JsonRoot: ");
            }

            switch (ele.GetType())
            {
                case ZMJsonElementType.XJET_VALUE:
                    {
                        Console.Write("\"" + ele.GetValue() + "\"");
                        break;
                    }

                case ZMJsonElementType.XJET_OBJECT:
                    {
                        Console.WriteLine("{");
                        for (int i = 0; i < ele.Objects.Count; i++)
                        {
                            dump(ele.Objects.ElementAt(i).Value, lv + 1);
                            if (i != ele.Objects.Count - 1)
                            {
                                Console.Write(",");
                            }
                            Console.WriteLine("");
                        }
                        for (int i = 0; i < lv; i++) Console.Write("    ");
                        Console.Write("}");

                        break;
                    }

                case ZMJsonElementType.XJET_ARRAY:
                    {
                        Console.WriteLine("[");
                        for (int i = 0; i < ele.Children.Count; i++)
                        {
                            String oldkey = ele.Children.ElementAt(i).GetKey();
                            ele.Children.ElementAt(i).SetKey("[" + i.ToString() + "]");
                            dump(ele.Children.ElementAt(i), lv + 1);
                            ele.Children.ElementAt(i).SetKey(oldkey);

                            if (i != ele.Children.Count - 1)
                            {
                                Console.Write(",");
                            }
                            Console.WriteLine("");
                        }
                        for (int i = 0; i < lv; i++) Console.Write("    ");
                        Console.Write("]");

                        break;
                    }
            }

            if (lv == 0) Console.WriteLine("");
        }

        /// <summary>
        /// DUMP函数 (用于调试)
        /// </summary>
        public void dump()
        {
            if (root == null)
            {
                Console.WriteLine("No any json information...");
            }
            dump(root, 0);
        }
        #endregion

        #region 内部分析函数
        /// <summary>
        /// 分析某元素键名
        /// </summary>
        /// <returns>键名</returns>
        protected String ParseKey()
        {
            try
            {
                /** 找双引号(为了读取键名) */
                ParsingPosition = MoveToNoneSpace(ParsingPosition);
                //if('"' != ParsingString[ParsingPosition]) return null;

                /** 读取键名 */
                String key = "";
                int dswyh;///< 单双无引号
                if ('\"' == ParsingString[ParsingPosition]) dswyh = 1;
                else if ('\'' == ParsingString[ParsingPosition]) dswyh = 0;
                else dswyh = 2;
                String yhidx = "'\"";

                if (2 != dswyh) ParsingPosition++;
                while (ParsingPosition < ParsingString.Length && (dswyh == 2 || (dswyh != 2 && ParsingString[ParsingPosition] != yhidx[dswyh])))
                {
                    if (2 == dswyh && ':' == ParsingString[ParsingPosition]) break;

                    /** Unicode转义 */
                    if (IsHexUnicode(ParsingPosition))
                    {
                        key += GetHexUnicode(ParsingPosition);
                        ParsingPosition += 6;
                        continue;
                    }

                    /** 普通转义 */
                    if ('\\' == ParsingString[ParsingPosition])
                    {
                        ParsingPosition++;
                        key += WhichTrans(ParsingPosition);
                        ParsingPosition++;
                        continue;
                    }

                    /** 非转义 */
                    key += ParsingString[ParsingPosition];
                    ParsingPosition++;
                }
                if (dswyh != 2) ParsingPosition++;
                if (ParsingPosition >= ParsingString.Length) return null;

                /** 读取冒号 */
                ParsingPosition = MoveToNoneSpace(ParsingPosition);
                if (':' != ParsingString[ParsingPosition]) return null;
                ParsingPosition++;

                if (dswyh == 2) key = key.Trim();

                return key;
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// 分析某元素键值
        /// </summary>
        /// <returns>元素体引用</returns>
        protected ZMJsonElement ParseBody()
        {
            ZMJsonElement Ele = new ZMJsonElement();
            ParsingPosition = MoveToNoneSpace(ParsingPosition);

            try
            {
                switch (ParsingString[ParsingPosition])
                {
                    /** 字符串 */
                    case '"':
                    case '\'':
                        {
                            //ParsingPosition++;
                            String value = GetStringValue();
                            ParsingPosition++;

                            Ele.SetValue(value);
                            Ele.SetType(ZMJsonElementType.XJET_VALUE);

                            return Ele;
                        }

                    /** Json对象：子节点 */
                    case '{':
                        {
                            Ele.SetType(ZMJsonElementType.XJET_OBJECT);
                            while (true)
                            {
                                ZMJsonElement Child;

                                ParsingPosition++;
                                ParsingPosition = MoveToNoneSpace(ParsingPosition);

                                /** 创建子节点 */
                                Child = ParserElement();
                                Ele.Objects[Child.GetKey()] = Child;

                                /** 子节点损坏 */
                                if (null == Child) return null;

                                ParsingPosition = MoveToNoneSpace(ParsingPosition);

                                /** 看看是不是逗号 */
                                if (',' == ParsingString[ParsingPosition])
                                {
                                    continue;
                                }

                                /** 看看是不是回括号 */
                                if ('}' == ParsingString[ParsingPosition])
                                {
                                    ParsingPosition++;
                                    ParsingPosition = MoveToNoneSpace(ParsingPosition);
                                    return Ele;
                                }
                            }
                        }

                    /** Json数组 */
                    case '[':
                        {
                            Ele.SetType(ZMJsonElementType.XJET_ARRAY);
                            while (true)
                            {
                                ZMJsonElement Child;
                                ParsingPosition++;
                                ParsingPosition = MoveToNoneSpace(ParsingPosition);

                                /** 子节点 */
                                Child = ParseBody();
                                Ele.Children.Add(Child);

                                /** 子节点损坏 */
                                if (null == Child) return null;

                                ParsingPosition = MoveToNoneSpace(ParsingPosition);

                                /** 看看是不是逗号 */
                                if (',' == ParsingString[ParsingPosition])
                                {
                                    continue;
                                }

                                /** 看看是不是回括号 */
                                if (']' == ParsingString[ParsingPosition])
                                {
                                    ParsingPosition++;
                                    ParsingPosition = MoveToNoneSpace(ParsingPosition);
                                    return Ele;
                                }
                            }
                        }

                    default:
                        {
                            Ele.SetType(ZMJsonElementType.XJET_VALUE);

                            ParsingPosition = MoveToNoneSpace(ParsingPosition);
                            String str = "";
                            while (' ' != ParsingString[ParsingPosition] &&
                                '\t' != ParsingString[ParsingPosition] &&
                                '\r' != ParsingString[ParsingPosition] &&
                                '\n' != ParsingString[ParsingPosition] &&
                                '}' != ParsingString[ParsingPosition] &&
                                ']' != ParsingString[ParsingPosition] &&
                                ',' != ParsingString[ParsingPosition]
                                )
                            {
                                str += ParsingString[ParsingPosition];
                                ParsingPosition++;
                            }
                            Ele.SetValue(str);
                            ParsingPosition = MoveToNoneSpace(ParsingPosition);

                            return Ele;
                        }
                }
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// 分析某元素 (包括键值和键名)
        /// </summary>
        /// <returns>元素引用</returns>
        protected ZMJsonElement ParserElement()
        {
            try
            {
                /** 元素节点 */
                ZMJsonElement Ele;

                /** 分析名字 */
                String key = ParseKey();

                /** 分析节点 */
                Ele = ParseBody();
                Ele.SetKey(key);

                return Ele;
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// 获取字符串值 （被转义之前）
        /// </summary>
        /// <returns>字符串</returns>
        private String GetStringValue()
        {
            bool syh = (ParsingString[ParsingPosition] == '"');
            ParsingPosition++;

            String key = "";
            while (ParsingPosition < ParsingString.Length && ((ParsingString[ParsingPosition] != '"' && syh) || (ParsingString[ParsingPosition] != '\'' && !syh)))
            {
                /** Unicode转义 */
                if (IsHexUnicode(ParsingPosition))
                {
                    key += GetHexUnicode(ParsingPosition);
                    ParsingPosition += 6;
                    continue;
                }

                /** 普通转义 */
                if ('\\' == ParsingString[ParsingPosition])
                {
                    ParsingPosition++;
                    key += WhichTrans(ParsingPosition);
                    ParsingPosition++;
                    continue;
                }

                /** 非转义 */
                key += ParsingString[ParsingPosition];
                ParsingPosition++;
            }

            return key;
        }

        /// <summary>
        /// 获取普通转义字符 (回车\换行\Tab等)
        /// </summary>
        /// <param name="Position">分析位置</param>
        /// <returns>字符</returns>
        private char WhichTrans(int Position)
        {
            if (Position >= ParsingString.Length) return ' ';

            switch (ParsingString[Position])
            {
                case 't': return '\t';
                case 'n': return '\n';
                case 'r': return '\r';

                default: return ParsingString[Position];
            }
        }

        /// <summary>
        /// 判断是否是16进制字符 (0123456789ABCDEF)
        /// </summary>
        /// <param name="ch">字符</param>
        /// <returns>是或否</returns>
        private bool IsHex(Char ch)
        {
            if (ch >= '0' && ch <= '9') return true;
            if (ch >= 'a' && ch <= 'f') return true;
            if (ch >= 'A' && ch <= 'F') return true;
            return false;
        }

        /// <summary>
        /// 在确定是Unicode转义的情况下获得Unicode
        /// </summary>
        /// <param name="Position">分析位置</param>
        /// <returns>结果字符串</returns>
        private String GetHexUnicode(int Position)
        {
            try
            {
                String HexA = ParsingString.Substring(Position + 2, 2);
                String HexB = ParsingString.Substring(Position + 4, 2);
                byte[] h = {
                               Convert.ToByte(HexB, 16),
                               Convert.ToByte(HexA, 16)
                           };

                return System.Text.Encoding.Unicode.GetString(h);
            }
            catch (Exception)
            {
                return "";
            }
        }

        /// <summary>
        /// 判断是否\u0000 - \uFFFF转义，即Unicode
        /// </summary>
        /// <param name="Position">分析位置</param>
        /// <returns>是否</returns>
        private bool IsHexUnicode(int Position)
        {
            if (Position + 5 < ParsingString.Length)
            {
                if (ParsingString[Position] != '\\') return false;
                if (ParsingString[Position + 1] != 'u') return false;

                for (int i = 2; i < 6; i++)
                {
                    if (!IsHex(ParsingString[Position + i])) return false;
                }

                return true;
            }

            return false;
        }

        /// <summary>
        /// 移动到非空格字符
        /// </summary>
        /// <param name="Position">当前位置</param>
        /// <returns>移动之后的位置</returns>
        private int MoveToNoneSpace(int Position)
        {
            Char[] sp = {
               ' ',
               '\t',
               '\n',
               '\r'
            };

            while (Position < ParsingString.Length)
            {
                bool moved = false;
                for (int i = 0; i < 4; i++)
                {
                    if (sp[i] == ParsingString[Position])
                    {
                        moved = true;
                        Position++;
                        break;
                    }
                }

                if (!moved) break;
            }

            return Position;
        }
        #endregion
    }
}
